import threading
import queue
import time
import random


class ProducerConsumerQueue:
    def __init__(self, max_size=10):
        """
        初始化生产者消费者队列

        Args:
            max_size (int): 队列最大容量
        """
        self.queue = queue.Queue(maxsize=max_size)
        self.lock = threading.Lock()
        self.producer_count = 0
        self.consumer_count = 0

    def produce(self, item, producer_name="Producer"):
        """
        生产项目（线程安全）

        Args:
            item: 要生产的项目
            producer_name (str): 生产者名称
        """
        try:
            self.queue.put(item, block=True, timeout=5)
            with self.lock:
                self.producer_count += 1
                print(f"{producer_name} 生产: {item} (总计: {self.producer_count})")
        except queue.Full:
            print(f"{producer_name} 无法生产 {item} - 队列已满")

    def consume(self, consumer_name="Consumer"):
        """
        消费项目（线程安全）

        Args:
            consumer_name (str): 消费者名称

        Returns:
            消费的项目，如果队列为空则返回None
        """
        try:
            item = self.queue.get(block=True, timeout=5)
            with self.lock:
                self.consumer_count += 1
                print(f"{consumer_name} 消费: {item} (总计: {self.consumer_count})")
            self.queue.task_done()
            return item
        except queue.Empty:
            print(f"{consumer_name} 无法消费 - 队列为空")
            return None

    def get_stats(self):
        """获取队列统计信息"""
        with self.lock:
            return {
                'queue_size': self.queue.qsize(),
                'producer_count': self.producer_count,
                'consumer_count': self.consumer_count,
                'unfinished_tasks': self.queue.unfinished_tasks
            }


def producer_thread(pc_queue, producer_id, items_to_produce):
    """
    生产者线程函数

    Args:
        pc_queue (ProducerConsumerQueue): 队列实例
        producer_id (int): 生产者ID
        items_to_produce (int): 要生产的项目数量
    """
    producer_name = f"生产者-{producer_id}"

    for i in range(items_to_produce):
        item = f"产品-{producer_id}-{i + 1}"
        pc_queue.produce(item, producer_name)
        time.sleep(random.uniform(0.1, 0.5))  # 模拟生产时间


def consumer_thread(pc_queue, consumer_id, items_to_consume):
    """
    消费者线程函数

    Args:
        pc_queue (ProducerConsumerQueue): 队列实例
        consumer_id (int): 消费者ID
        items_to_consume (int): 要消费的项目数量
    """
    consumer_name = f"消费者-{consumer_id}"
    consumed_count = 0

    while consumed_count < items_to_consume:
        item = pc_queue.consume(consumer_name)
        if item is not None:
            consumed_count += 1
        time.sleep(random.uniform(0.1, 0.8))  # 模拟消费时间


def main():
    """主函数演示多线程生产者消费者模式"""
    # 创建队列
    pc_queue = ProducerConsumerQueue(max_size=5)

    # 配置生产者和消费者
    num_producers = 3
    num_consumers = 2
    items_per_producer = 5
    items_per_consumer = 8  # 消费者总数应该 >= 生产者总数

    # 创建并启动生产者线程
    producer_threads = []
    for i in range(num_producers):
        thread = threading.Thread(
            target=producer_thread,
            args=(pc_queue, i + 1, items_per_producer)
        )
        producer_threads.append(thread)
        thread.start()

    # 创建并启动消费者线程
    consumer_threads = []
    for i in range(num_consumers):
        thread = threading.Thread(
            target=consumer_thread,
            args=(pc_queue, i + 1, items_per_consumer)
        )
        consumer_threads.append(thread)
        thread.start()

    # 等待所有生产者完成
    for thread in producer_threads:
        thread.join()

    # 等待所有消费者完成
    for thread in consumer_threads:
        thread.join()

    # 等待队列中所有任务完成
    pc_queue.queue.join()

    # 打印最终统计信息
    stats = pc_queue.get_stats()
    print("\n=== 最终统计 ===")
    print(f"队列大小: {stats['queue_size']}")
    print(f"总生产数量: {stats['producer_count']}")
    print(f"总消费数量: {stats['consumer_count']}")
    print(f"未完成任务: {stats['unfinished_tasks']}")


if __name__ == "__main__":
    main()